home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power Programmierung
/
Power-Programmierung (Tewi)(1994).iso
/
assemblr
/
library
/
sampler0
/
pcterm.asm
< prev
next >
Wrap
Assembly Source File
|
1990-02-11
|
18KB
|
571 lines
;--------------------------------------------------------------------
; DUMBTERM
; Original author is CJ Dunford 09/12/83, modified by Jeff Firestone
; on 01/15/84. This program sets up the interrupt for COM1. It uses
; buffered communications. The program is based upon PC Tech Journal
; Jan '84, p144-186.
;---------------------------------------------------------------------
bufsize equ 4096 ;4K Buffer
LF equ 0Ah
CR equ 0Dh
K_ESC equ 1Bh
; ------- BIOS calls
RS232 equ 14h ;RS232 service
kbd_io equ 16h ;Keyboard service
; ------- INS8250 registers
THR equ 3F8h ;Trans holding register (write)
RBR equ 3F8h ;Recieve buffer register (read)
IER equ 3F9h ;Interrupt inable register
LCR equ 3FBh ;Line control register
; Bit 7 of LCR is "DLAB". DLAB must
; be zero to access THR, RBR, IER.
MCR equ 3FCh ;Modem control register
LSR equ 3FDh ;Line status register
MSR equ 3FEh ;Modem status register
; ------- Comm parameter definition
; Refer to IBM Tech Ref manual page A-20
; See PROC INIT for usage.
; ---------------------------------------
commparm record baud:3, parity:2, stopbits:1, wordbits:2
; Buad rates
B110 equ 000b
B150 equ 001b
B300 equ 010b
B600 equ 011b
B1200 equ 100b
B2400 equ 101b
B4800 equ 110b
B9600 equ 111b
; Parity
no_parity equ 00b
odd_parity equ 01b
even_parity equ 11b
; Stop bits
stop1 equ 0
stop2 equ 1
; Data bits
data7 equ 10b
data8 equ 11b
;*****************************
; MACROS
;*****************************
@bioscall MACRO call_num, parm
;; Generates an 'INT call_num', with parm in AH
IFNB <parm>
mov ah,parm
ENDIF
int call_num
ENDM
@doscall MACRO function, parm
;; Generates a DOS function call with parm in AH
IFNB <parm>
mov al,parm
ENDIF
@bioscall 21h,function
ENDM
;******************************
; DATA & STACK SEGMENTS
;******************************
data segment para public 'data'
; ----- The string section
sgreeting db '--- ONLINE -0--',cr,lf,'$'
sgoodbye db cr,lf,'--- OFFLINE ---',cr,lf,'$'
serr1 db '<R>$' ;RS232 receive error
serr2 db '<S>$' ;RS232 send error
serr3 db '<B>$' ;Receive buffer overflow error
; ----- Flags
brcv_err db 0 ;Nonzero on RS232 receive error
boverflow db 0 ;Nonzero on buffer overflow
bdoneflag db 0 ;Nonzero after ESC from kbd
; ----- Receive data buffer and associated pointers
; >> Buffer is empty if head point4er = tail pointer
wbufhead dw buffer ;Pointer to head of buffer
wbuftail dw buffer ;Pointer to tail of buffer
buffer db BUFSIZE dup (?)
bufend equ $
data ends
; ----- Stack
stack segment para stack 'stack'
db 256 dup (?)
stack ends
;* * * * * * * * * * * * * * * * *
; PROGRAM BODY
;* * * * * * * * * * * * * * * * *
code segment para public 'code'
assume cs:code, ds:data, ss:stack
main proc far
; ------ Initialize
push ds ;Set up long return to DOS
sub ax,ax
push ax
call init ;Rest of initialization
; ------ Main program loop
M100: call buffer_check ;Check RS232 buffer, display if char
call kb_check ;Check kbd, Send to RS232.
test bdoneflag,0FFh ;Non-zero if done
jz M100 ;Loop till ESC received
; ------ ESC received. Clean up interrupt & exit
call cleanup
ret ;Return to DOS
main endp
;* * * * * * * * * * * * * * * * * * * *
; PRIMARY BLOCKS
;* * * * * * * * * * * * * * * * * * * *
; ------ Init ---------------------------------
;Program initialization
; set up RS232
; set up vector for RS232 interrupt (INT 0Ch)
; Enable IRQ4
; Enable RS232 interrupt on data ready
; --------------------------------------------
init proc near
; ----- Initialize RS232 300,8,N,1
mov dx,0
mov al,commparm <B9600,even_Parity,stop1,data7>
@bioscall RS232,0
; ----- Set up INT '0C' for IRQ4
cli ;Interrupts off during setup
push ds ;Save DS
mov dx,offset ISR ;Point to RS232 ISR in DS:DX
push cs
pop ds
@doscall 25h,0Ch ;Set vector intr for IRQ4
pop ds ;Restore DS
; ------ Enable IRQ4 on 8259 interrupt controller
in al,21h ;Get current mask
and al,11101111b ;Reset IRQ4 mask
out 21h,al ;restore to IMR
; ------ Enable 8250 data ready interrupt
mov dx,LCR ;DX <== LCR
in al,dx ;reset DLAB for IER access
and al,01111111b
out dx,al
mov dx,IER ;address IER
mov al,00000001b ;Enable data-ready interrupt
out dx,al
; ------ Enable OUT2 on 8250
mov dx,MCR ;Address MCR
mov al,00001000b ;Enable OUT2
out dx,al
sti
; ------ Display greeting & return
mov ax,data ;Establish data seg address
mov ds,ax
mov dx,offset sgreeting ;Point to greeting
call strdisp ;Display it
ret
init endp
; ------ Buffer Check ------------------
; RS232 buffer check
;
; This block checks the received data buffer.
; It functions as follows:
;
; If the RS232 input buffer is not empty
; Get the first character
; Display the character
; Update buffer pointer
; If the RS232 receive error flag is nonzero
; Display an error indicator
;
; Entry:
; No requirement
; Exit
; AX, BX, DX destroyed
; --------------------------------------
buffer_check proc near
; ------ Check buffer status
mov bx,wbufhead ;buffer head pointer
cmp bx,wbuftail ;buffer empty if head = tail
je BC100
; ------ Something in buffer--get 1st char, fix pointers
mov al,[bx] ;get the char
call incptr ;Bump buffer head pointer
mov wbufhead,bx
; ------ Display character received. Filter CR/LF
cmp al,LF ;Is it a line feed
je BC100 ;Skip display if yes
call chdisp ;Display if no
cmp al,CR
jne BC100
mov al,LF
call chdisp
; ------ Test RS232 receive status; display errors
BC100: Test brcv_err,0FFh ;Flag nonzero if errors
jz BC200 ;Jump if no errors
mov dx,offset serr1 ;Point to error msg
call strdisp
mov brcv_err,0 ;Clear error flag
; ----- Test for buffer overflow; display errors
BC200:
test boverflow, 0FFh
jz BC300
mov boverflow,0 ;Clear the flag
mov dx,offset serr3 ;Point to error msg
call strdisp
BC300: ret
buffer_check endp
; ----- KB_CHECK -----------------------------------
; Check the keyboard. Functions as follows
;
; Check the keyboard status
; If a characteris available
; If the character is ESC
; set the done flag
; ELSE
; send it to RS232 and watch for errors
;
; This routine does not echo the characters to the display.
;
; Entry:
; No requirement
; Exit
; AX, DX destroyed
; --------------------------------------
kb_check proc near
; ----- Poll keyboard, check chars received
call kb_poll ;Poll the keyboard
jz KBC900 ;Kbd clear, exit
cmp al,K_ESC ;Escape?
jne KBC100
mov bdoneflag,0FFh ;Yes, set terminate flag
jmp short KBC900
; ----- Send the received char, watch for errors
KBC100: Call RS232_out ;Send it
test ah,80h ;Time out?
jz KBC900
mov dx,offset serr2 ;Point to error msg
call strdisp ; and display
KBC900: ret
kb_check endp
; ----- ISR ------------------------------------------------------
; This is the RS232 interrupt service routine. It is entered
; whenever the RS232 port interrupts on a 'data ready'
; condition. The routine simply reads the data from the asynch
; chip and stuffs it in the buffer. Note that the process of reading
; the received data register in the 8250 clears IRQ4. However, the
; 8259 must be told specifically that the interrupt service is complete.
;
; This replaces the function 2 of BIOS interrupt 14h (receive a character
; over the comm line). Since it cannot return errors in a register, it
; puts the error marker in memory at 'brcv_err'. The error flag is
; sticky -- a successful read will not clear a prior error indication.
; This allows the program mainline to examine the error status at its
; leisure. Error bits are the same as in RS232OUT, above, except that
; ONLY the error bits are set, and bit 7 is not used (always 0). In
; other words, brcv_err is nonzero only on an error. Timeout errors
; are not possible here.
;
; The ISR will set the overflow flag if the buffer should overflow.
; This shouldn't happen.
; --------------------------------------------------------------------
ISR proc near
sti ;Allow other interrupts
push ax ;Save all regs used
push bx
push dx
push si
push ds
; ---- Establish data addressability
mov ax,data
mov ds,ax
; ---- Get error bits
mov dx,LSR ;Save address of RS232
in al,dx ;Get status
and al,00011110b ;Mask non-error bits
jz ISR010 ;Skip error set if OK
mov brcv_err,al ;Set error indicator
; ---- Get incoming character and buffer it
ISR010: mov dx,RBR ;Receive buffer
in al,dx ;Get input buffer
mov bx,wbuftail ;Buffer input pointer
mov si,bx ;Set pointer before increment
call incptr ;Bump input pointer
cmp bx,wbufhead ;Overflow if head = tail
je ISR020 ;Overflow
mov [si],al ;No overflow, save char in buf
mov wbuftail,bx ;And new input pointer
jmp short ISR999
ISR020: mov boverflow, 0FFh ;Set overflow flag
; ---- Signal end of interrupt to 8259
ISR999: cli
mov al,20h ;Non-specific EOI
out 20h,al ;Send it
; ---- Restore regs & return. IRET reenables interrupts
pop ds
pop si
pop dx
pop bx
pop ax
iret
ISR endp
; ---- CLEANUP --------------------
; End of program housekeeping
; -- Disable IRQ4
; -- Disable 8250 interrupts
; -- Disable OUT2
; -- Display offline message
; ---------------------------------
cleanup proc near
; ---- Disable IRQ4 on 8259
cli
in al,21h ;IMR
or al,00010000b ;Mask bit 4 -- IRQ4
out 21h,al
; ---- Disable 8250 data ready interrupt
mov dx, LCR ;DX <=== LCR
in al,dx ;Reset DLAB for IER access
and al,01111111b
out dx,al
mov dx,IER ;Address IER
mov al,0 ;Disable all 8250 interrupts
out dx,al
; ---- Disable OUT2 on 8250
mov dx,MCR ;Address MCR
mov al,0 ;Disable OUT2
out dx,al
sti
; ---- Display bye-bye
mov dx,offset sgoodbye
call strdisp
cleanup endp
; * * * * * * * * * * * * * *
; I/O & General Subroutines
; * * * * * * * * * * * * * *
; ---- KB_POLL ------------------------------
; Set/reset Z flag on keyboard buffer status.
;
; Entry:
; No requirements
; Exit:
; Z = 1 if nothing available
; Z = 0 if char available from kbd
; IF Z = 0
; AL = char
; AH = scan code
; Other regs preserved
; ---------------------------------------------
kb_poll proc near
@bioscall kbd_io,1 ;Poll KB. Sets Z flag if KB bfr empty
jz KB999 ;Nothing there
pushf ;Save flag status
@bioscall kbd_io,0 ;Something there; get it
popf
KB999:
ret
kb_poll endp
; -- RS232_OUT ----------------------------------------
; RS232 output routine
;
; This routine sends one character to the RS232 port.
; It replaces function 1 of BIOS int 14K. This is
; necessary because BIOS will disable the RS232
; interrupt (by disabling OUT2) every time it is
; called.
;
; Entry:
; AL = character to be transmitted
; Exit:
; AH = send status
; Bit 7 = 1 if RS232 timeout occurred
; If bit 7 = 0
; bit 6: trans shift register empty
; bit 5: trans holding register empty
; bit 4: break detect
; bit 3: framing error
; bit 2: parity error
; bit 1: overrun error
; bit 0: data ready
; Other regs preserved.
; -------------------------------------------------------
RS232_out proc near
push bx ;Save regs used
push cs
push dx
; ----- Set up RS232
mov bl,al ;Save char to bl temporarily
mov dx,MCR ;Modem Control Register
mov al,00001011b ; OUT2, DTR, RTS
out dx,al
sub cx,cx ;Initialize timeout count
mov dx,MSR ;Modem Status Register
; ----- Wait for DSR
RS100:
in al,dx
test al,20h ;Data set ready?
jnz RS150 ;Yes
loop RS100 ;No, retry till timeout
mov ah,80h ;Set timeout
jmp short RSXIT ;and quit
; ----- Wait for CTS
RS150:
sub cx,cx ;Another timeout count
RS200:
in al,dx
test al,10h ;Clear to send?
jnz RS250 ;Yes
loop RS200 ;No, loop till timeout
mov ah,80h ;TImeout,set flag
jmp short RSXIT ;And quit
; ----- Wait for THRE
RS250:
mov dx,LSR ;Line Status Register
sub cx,cx ;Yes another timeout count
RS300:
in al,dx ;LSR status
test al,20h ;Transmit holding reg empty?
jnz RS350 ;Yes
loop RS300 ;No, loop till timeout
mov ah,80h ;Timeout, set flag
jmp short RSXIT
; ------ Get line status, send char
RS350:
mov ah,al ;Get line status for return
and ah,01111111b ;Mask out bit 7
mov al,bl ;Restore char to AL
mov dx,THR ;Transmit holding register
out dx,al ;Output it to RS232
RSXIT:
pop dx
pop cx
pop bx
ret
RS232_out endp
; ---- CHDISP ----------------------------------
; Display the character in AL on the CRT
; Entry:
; AL = char
; Exit:
; All regs restored
; ----------------------------------------------
chdisp proc near
push ax
push dx
mov dl,al
@doscall 2
pop dx
pop ax
ret
chdisp endp
; ---- STRDISP ----------------------------
; Display the string at DS:DX on the CRT
; Entry:
; DS:DX ==> string
; Exit:
; All regs restored
; -----------------------------------------
strdisp proc near
push ax
@doscall 9
pop ax
ret
strdisp endp
; ----- INCPTR ------------------------------
; Increments the buffer pointer in reg BX.
; If the pointer goes beyond the end of the
; buffer, wrap around to start.
;
; Entry:
; BX = buffer pointer
; Exit
; BX = advanced buffer pointer
; Other regs restored
; --------------------------------------------
incptr proc near
inc bx ; Bump pointer
cmp bx,offset bufend ; Past end?
jne IP100 ; Jump if not
mov bx,offset buffer ; Else point to start
IP100:
ret
incptr endp
code ends
end main